package edu.stanford.travelhard;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.sql.Timestamp;
import java.util.Date;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;

import android.os.Handler;
import android.os.Message;
import android.util.Log;

/**
 * Utility class implementing a Publisher runnable to transmit a
 * Media object to the server.
 * 
 * @author Nate Hardison
 *
 */
public class Publisher implements Runnable {
    
	public static final int PUBLISH_SUCCEEDED = 1;
	public static final int PUBLISH_FAILED = 2;
	
	private static final String UPLOAD_URL = "http://hardon.stanford.edu/postMedia.php";
	
	private Media mMedia;
	private Handler mHandler;
	
	public Publisher(Media media, Handler handler) {
		mMedia = media;
		mHandler = handler;
	}
	
	public void run() {
		publish();
	}
	
    private void publish() {
    	HttpClient httpClient = new DefaultHttpClient();
		HttpPost httpPost = new HttpPost(UPLOAD_URL);
			
    	try {
    		httpPost.setEntity(buildEntity(mMedia));
    		Log.i("PUBLISH", "Publishing: " + mMedia.toString());
			httpClient.execute(httpPost, new ResponseHandler<Void>() {
				public Void handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
					int statusCode = response.getStatusLine().getStatusCode();
					if (statusCode == 200) {
						mMedia.setTimePublished(new Timestamp(new Date().getTime()));
						Log.i("PUBLISH", "Published: " + mMedia.toString());
						
						DatabaseHelper dbhh = TravelCore.getDBH();
						dbhh.open();
						dbhh.setPublished(mMedia);
						dbhh.close();
						
						sendResponse(PUBLISH_SUCCEEDED, mMedia.getTimePublished());
					} else {
						Log.w("PUBLISH", "Publish failed! " + response.toString());
						sendResponse(PUBLISH_FAILED, "Received response: " + response.toString());
					}
					return null;
				}
			});
    	} catch (UnsupportedEncodingException e) {
    		e.printStackTrace();
    		sendResponse(PUBLISH_FAILED, "Unsupported encoding: " + e.getMessage());
		} catch (ClientProtocolException e) {
			e.printStackTrace();
			sendResponse(PUBLISH_FAILED, "Client protocol exception: " + e.getMessage());
		} catch (IOException e) {
			e.printStackTrace();
			sendResponse(PUBLISH_FAILED, "I/O exception: " + e.getMessage());
		}
    }
    
    private void sendResponse(int responseCode, Object responseObj) {
    	try {
    		Message msg = mHandler.obtainMessage(responseCode);
    		msg.obj = responseObj;
    		mHandler.sendMessage(msg);
    	} catch (NullPointerException e) {
    		Log.w("PUBLISHER", "Handler is gone...");
    		e.printStackTrace();
    	}
    }
    
    /**
     * Builds a MultipartEntity from the given media object.
     * @param m
     * @return
     * @throws UnsupportedEncodingException
     */
    private MultipartEntity buildEntity(Media m) throws UnsupportedEncodingException {
		MultipartEntity entity = new MultipartEntity();
		
		// Translate our Date value into a Timestamp that SQL can understand
		Timestamp timeCaptured = new Timestamp(m.getTimeCaptured().getTime());
		
		entity.addPart("trip_id", new StringBody(m.getTripID().toString()));
		entity.addPart("media_type", new StringBody(m.getType().toString()));
		entity.addPart("latitude", new StringBody(m.getLat().toString()));
		entity.addPart("longitude", new StringBody(m.getLng().toString()));
		entity.addPart("altitude", new StringBody(m.getAlt().toString()));
		entity.addPart("time_captured", new StringBody(timeCaptured.toString()));
		
		if (m.getAudioFilename() != null) {
			File audioFile = new File(m.getAudioFilename());
			if (audioFile != null && audioFile.exists() && audioFile.length() > 0) {
				entity.addPart("audio_file", new FileBody(audioFile));
			}
		}
		
		entity.addPart("photo_file", new FileBody(new File(m.getPhotoFilename())));
		entity.addPart("photo_orientation", new StringBody(m.getPhotoOrientation().toString()));
		
		return entity;
	}
    
}
